package com.tanx.cqrs.event.store;

import com.tanx.cqrs.event.Event;

import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;


public class MemoryEventStoreRepository implements EventStoreRepository {

    private CopyOnWriteArraySet<MemoryEventProxy> storage = new CopyOnWriteArraySet<>();

    @Override
    public List findByCreateDateTimeAfterAndIdByCreateDateTimeAsc(Date date, Object o) {
        return storage.stream().filter(new Predicate<MemoryEventProxy>() {
            @Override
            public boolean test(MemoryEventProxy eventProxy) {
                return eventProxy.getEvent().getAggregateId().equals(o.toString())
                        && eventProxy.getCreateDateTime().after(date) && !eventProxy.getStatus().equals(EventStatus.FINISH);
            }
        }).sorted(new Comparator<MemoryEventProxy>() {
            @Override
            public int compare(MemoryEventProxy o1, MemoryEventProxy o2) {
                return o1.getCreateDateTime().compareTo(o2.getCreateDateTime());
            }
        }).collect(Collectors.toList());
    }

    @Override
    public List findByIdByCreateDateTimeAsc(Object o) {
        return storage.stream().filter(new Predicate<MemoryEventProxy>() {
            @Override
            public boolean test(MemoryEventProxy eventProxy) {
                return eventProxy.getEvent().getAggregateId().equals(o.toString()) && !eventProxy.getStatus().equals(EventStatus.FINISH);
            }
        }).sorted(new Comparator<MemoryEventProxy>() {
            @Override
            public int compare(MemoryEventProxy o1, MemoryEventProxy o2) {
                return o1.getCreateDateTime().compareTo(o2.getCreateDateTime());
            }
        }).collect(Collectors.toList());
    }

    @Override
    public boolean save(Event eventProxy) {
        return storage.add(new MemoryEventProxy(eventProxy));
    }

    @Override
    public boolean delete(Event event) {
        Set<MemoryEventProxy> collect = storage.stream().filter(eventProxy -> eventProxy.getEvent().getUuid().equals(event.getUuid())).collect(Collectors.toSet());
        return storage.removeAll(collect);
    }

    @Override
    public void finishEvent(String s) {
        storage.stream().filter(new Predicate<MemoryEventProxy>() {
            @Override
            public boolean test(MemoryEventProxy eventProxy) {
                return eventProxy.getEvent().getUuid().equals(s);
            }
        }).forEach(new Consumer<MemoryEventProxy>() {
            @Override
            public void accept(MemoryEventProxy memoryEventProxy) {
                memoryEventProxy.setStatus(EventStatus.FINISH);
            }
        });
    }

    @Override
    public Event findByEventId(String s) {
        Optional<MemoryEventProxy> first = storage.stream().filter(new Predicate<MemoryEventProxy>() {
            @Override
            public boolean test(MemoryEventProxy eventProxy) {
                return eventProxy.getEvent().getUuid().equals(s);
            }
        }).findFirst();
        return first.map(MemoryEventProxy::getEvent).orElse(null);
    }

    @Override
    public List<MemoryEventProxy> findByUnFinishEventByCreateDateTimeAsc() {
        return storage.stream().filter(new Predicate<MemoryEventProxy>() {
            @Override
            public boolean test(MemoryEventProxy eventProxy) {
                return !eventProxy.getStatus().equals(EventStatus.FINISH);
            }
        }).sorted(new Comparator<MemoryEventProxy>() {
            @Override
            public int compare(MemoryEventProxy o1, MemoryEventProxy o2) {
                return o1.getCreateDateTime().compareTo(o2.getCreateDateTime());
            }
        }).collect(Collectors.toList());
    }
}
